[IA64] Check privilege level for pal/sal/efi calls.
authorawilliam@xenbuild.aw <awilliam@xenbuild.aw>
Mon, 20 Mar 2006 16:55:32 +0000 (09:55 -0700)
committerawilliam@xenbuild.aw <awilliam@xenbuild.aw>
Mon, 20 Mar 2006 16:55:32 +0000 (09:55 -0700)
Previously a user was able to reset the machine.

Signed-off-by: Tristan Gingold <tristan.gingold@bull.net>
xen/arch/ia64/xen/hypercall.c
xen/include/asm-ia64/dom_fw.h

index a639c9bca916a8f8a71cbe0a29564d11b8a279cb..e24a06fb711fe8082201da0f8ea706dd5fac376d 100644 (file)
@@ -66,13 +66,71 @@ hypercall_t ia64_hypercall_table[] =
        (hypercall_t)do_ni_hypercall            /*  */
        };
 
-int
-ia64_hypercall (struct pt_regs *regs)
+static int
+xen_hypercall (struct pt_regs *regs)
+{
+       switch (regs->r2) {
+           case __HYPERVISOR_dom0_op:
+               regs->r8 = do_dom0_op(guest_handle_from_ptr(regs->r14,
+                                                           dom0_op_t));
+               break;
+
+           case __HYPERVISOR_memory_op:
+               /* we don't handle reservations; just return success */
+               {
+                   struct xen_memory_reservation reservation;
+                   void *arg = (void *) regs->r15;
+
+                   switch(regs->r14) {
+                   case XENMEM_increase_reservation:
+                   case XENMEM_decrease_reservation:
+                       if (copy_from_user(&reservation, arg,
+                               sizeof(reservation)))
+                           regs->r8 = -EFAULT;
+                       else
+                           regs->r8 = reservation.nr_extents;
+                       break;
+                   default:
+                       regs->r8 = do_memory_op((int) regs->r14, guest_handle_from_ptr(regs->r15, void));
+                       break;
+                   }
+               }
+               break;
+
+           case __HYPERVISOR_event_channel_op:
+               regs->r8 = do_event_channel_op(guest_handle_from_ptr(regs->r14, evtchn_op_t));
+               break;
+
+           case __HYPERVISOR_grant_table_op:
+               regs->r8 = do_grant_table_op((unsigned int) regs->r14, guest_handle_from_ptr(regs->r15, void), (unsigned int) regs->r16);
+               break;
+
+           case __HYPERVISOR_console_io:
+               regs->r8 = do_console_io((int) regs->r14, (int) regs->r15, guest_handle_from_ptr(regs->r16, char));
+               break;
+
+           case __HYPERVISOR_xen_version:
+               regs->r8 = do_xen_version((int) regs->r14, guest_handle_from_ptr(regs->r15, void));
+               break;
+
+           case __HYPERVISOR_multicall:
+               regs->r8 = do_multicall(guest_handle_from_ptr(regs->r14, multicall_entry_t), (unsigned int) regs->r15);
+               break;
+
+           default:
+               printf("unknown xen hypercall %lx\n", regs->r2);
+               regs->r8 = do_ni_hypercall();
+       }
+       return 1;
+}
+
+
+static int
+fw_hypercall (struct pt_regs *regs)
 {
        struct vcpu *v = current;
        struct sal_ret_values x;
        unsigned long *tv, *tc;
-       int pi;
 
        switch (regs->r2) {
            case FW_HYPERCALL_PAL_CALL:
@@ -87,6 +145,7 @@ ia64_hypercall (struct pt_regs *regs)
                VCPU(v,pending_interruption) = 1;
 #endif
                if (regs->r28 == PAL_HALT_LIGHT) {
+                       int pi;
 #define SPURIOUS_VECTOR 15
                        pi = vcpu_check_pending_interrupts(v);
                        if (pi != SPURIOUS_VECTOR) {
@@ -165,66 +224,50 @@ ia64_hypercall (struct pt_regs *regs)
                // FIXME: need fixes in efi.h from 2.6.9
                regs->r8 = EFI_UNSUPPORTED;
                break;
-           case 0xffff:
-               regs->r8 = dump_privop_counts_to_user(
-                       (char *) vcpu_get_gr(v,32),
-                       (int) vcpu_get_gr(v,33));
-               break;
-           case 0xfffe:
-               regs->r8 = zero_privop_counts_to_user(
-                       (char *) vcpu_get_gr(v,32),
-                       (int) vcpu_get_gr(v,33));
-               break;
-           case __HYPERVISOR_dom0_op:
-               regs->r8 = do_dom0_op(guest_handle_from_ptr(regs->r14,
-                                                           dom0_op_t));
-               break;
+           default:
+               printf("unknown ia64 fw hypercall %lx\n", regs->r2);
+               regs->r8 = do_ni_hypercall();
+       }
+       return 1;
+}
 
-           case __HYPERVISOR_memory_op:
-               /* we don't handle reservations; just return success */
-               {
-                   struct xen_memory_reservation reservation;
-                   void *arg = (void *) regs->r15;
+int
+ia64_hypercall (struct pt_regs *regs)
+{
+       struct vcpu *v = current;
+       unsigned long index = regs->r2;
 
-                   switch(regs->r14) {
-                   case XENMEM_increase_reservation:
-                   case XENMEM_decrease_reservation:
-                       if (copy_from_user(&reservation, arg,
-                               sizeof(reservation)))
-                           regs->r8 = -EFAULT;
-                       else
-                           regs->r8 = reservation.nr_extents;
+       if (index >= FW_HYPERCALL_FIRST_USER) {
+           switch (index) {
+               case 0xffff:
+                       regs->r8 = dump_privop_counts_to_user(
+                               (char *) vcpu_get_gr(v,32),
+                               (int) vcpu_get_gr(v,33));
                        break;
-                   default:
-                       regs->r8 = do_memory_op((int) regs->r14, guest_handle_from_ptr(regs->r15, void));
+               case 0xfffe:
+                       regs->r8 = zero_privop_counts_to_user(
+                               (char *) vcpu_get_gr(v,32),
+                               (int) vcpu_get_gr(v,33));
                        break;
-                   }
-               }
-               break;
-
-           case __HYPERVISOR_event_channel_op:
-               regs->r8 = do_event_channel_op(guest_handle_from_ptr(regs->r14, evtchn_op_t));
-               break;
-
-           case __HYPERVISOR_grant_table_op:
-               regs->r8 = do_grant_table_op((unsigned int) regs->r14, guest_handle_from_ptr(regs->r15, void), (unsigned int) regs->r16);
-               break;
-
-           case __HYPERVISOR_console_io:
-               regs->r8 = do_console_io((int) regs->r14, (int) regs->r15, guest_handle_from_ptr(regs->r16, char));
-               break;
-
-           case __HYPERVISOR_xen_version:
-               regs->r8 = do_xen_version((int) regs->r14, guest_handle_from_ptr(regs->r15, void));
-               break;
-
-           case __HYPERVISOR_multicall:
-               regs->r8 = do_multicall(guest_handle_from_ptr(regs->r14, multicall_entry_t), (unsigned int) regs->r15);
-               break;
-
-           default:
-               printf("unknown hypercall %lx\n", regs->r2);
-               regs->r8 = do_ni_hypercall();
+               default:
+                       printf("unknown user xen/ia64 hypercall %lx\n", index);
+                       regs->r8 = do_ni_hypercall();
+           }
+           return 1;
        }
-       return 1;
+       else if (index >= FW_HYPERCALL_FIRST_ARCH) {
+           int privlvl;
+
+           /* Firmware calls are only allowed in kernel.  */
+           privlvl = (regs->cr_ipsr & IA64_PSR_CPL) >> IA64_PSR_CPL0_BIT;
+           if (privlvl != 2) {
+               /* FIXME: Return a better error value ?
+                  Reflextion ? Illegal operation ?  */
+               regs->r8 = -1;
+               return 1;
+           }
+           else
+               return fw_hypercall (regs);
+       } else
+           return xen_hypercall (regs);
 }
index 1c5f3d09aabc0ee841d41e77f19b1ffb31c57099..4060793697fcbf964bb2e782a1fa24621c32ec34 100644 (file)
@@ -119,6 +119,16 @@ extern unsigned long dom_fw_setup(struct domain *, char *, int);
 #define FW_HYPERCALL_EFI_GET_NEXT_HIGH_MONO_COUNT_PADDR        FW_HYPERCALL_PADDR(FW_HYPERCALL_EFI_GET_NEXT_HIGH_MONO_COUNT_INDEX)
 #define FW_HYPERCALL_EFI_RESET_SYSTEM_PADDR            FW_HYPERCALL_PADDR(FW_HYPERCALL_EFI_RESET_SYSTEM_INDEX)
 
+/* Hypercalls index bellow _FIRST_ARCH are reserved by Xen, while those above
+   are for the architecture.
+   Note: this limit was defined by Xen/ia64 (and not by Xen).²
+     This can be renumbered safely.
+*/
+#define FW_HYPERCALL_FIRST_ARCH                0x300UL
+
+/* Xen/ia64 user hypercalls.  Only used for debugging.  */
+#define FW_HYPERCALL_FIRST_USER                0xff00UL
+
 extern struct ia64_pal_retval xen_pal_emulator(UINT64, u64, u64, u64);
 extern struct sal_ret_values sal_emulator (long index, unsigned long in1, unsigned long in2, unsigned long in3, unsigned long in4, unsigned long in5, unsigned long in6, unsigned long in7);
 extern struct ia64_pal_retval pal_emulator_static (unsigned long);